package cn.catsdad.base.service.impl;

import cn.catsdad.base.entity.BaseCrudEntity;
import cn.catsdad.base.processor.IBaseServiceProcessor;
import cn.catsdad.base.repository.api.IBaseCrudRepository;
import cn.catsdad.base.service.api.IBaseCrudService;
import cn.catsdad.util.StringUtil;
import org.springframework.transaction.annotation.Transactional;

import java.io.Serializable;
import java.util.*;

/**
 * @author xuyl
 * @version 1.0 2024/8/29
 */
public abstract class BaseCrudServiceImpl<T extends BaseCrudEntity, ID extends Serializable, R extends IBaseCrudRepository<T, ID>>
        extends BaseServiceImpl<T, ID, R> implements IBaseCrudService<T, ID> {

    @Override
    @Transactional
    public void logicDeleteById(ID id) {
        if (id != null) {
            Optional<T> byId = repository.findById(id);
            byId.ifPresent(t -> doLogicDelete(Collections.singleton(t)));
        }
    }

    @Override
    @Transactional
    public void logicDeleteByIds(Collection<ID> ids) {
        if (StringUtil.isNotEmpty(ids)) {
            List<T> exists = repository.findAllById(ids);
            doLogicDelete(exists);
        }
    }

    @Override
    @Transactional
    public void logicDeleteByEntity(T entity) {
        doLogicDelete(Collections.singleton(entity));
    }

    @Override
    @Transactional
    public void logicDeleteByEntities(Collection<T> entities) {
        doLogicDelete(entities);
    }

    @Override
    public List<T> queryByIdsWithIsDeletedFalse(Collection<ID> ids) {
        return doIsDeletedFalseQuery(ids);
    }

    @Override
    public T queryByIdWithIsDeletedFalse(ID id) {
        List<T> list = doIsDeletedFalseQuery(Collections.singleton(id));
        if (StringUtil.isNotEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    @Override
    public Map<ID, T> queryMapWithIsDeletedFalse(Collection<ID> ids) {
        List<T> entities = doIsDeletedFalseQuery(ids);
        Map<ID, T> result = new HashMap<>();
        entities.forEach(e -> result.put((ID) e.getId(), e));
        return result;
    }

    private List<T> doIsDeletedFalseQuery(Collection<ID> ids) {
        List<T> result = new ArrayList<>();
        if (StringUtil.isNotEmpty(ids)) {
            List<IBaseServiceProcessor<T, ID>> practicalProcessor = getPracticalProcessor();
            for (IBaseServiceProcessor<T, ID> p : practicalProcessor) {
                result.addAll(p.preQuery(ids, repository.getEntityClass()));
            }
            if (StringUtil.isNotEmpty(result)) {
                result = repository.findByIdInAndIsDeletedFalse(ids);
            }
            for (IBaseServiceProcessor<T, ID> processor : practicalProcessor) {
                processor.postQuery(result);
            }
        }
        return result;
    }

    private void doLogicDelete(Collection<T> entities) {
        if (StringUtil.isNotEmpty(entities)) {
            List<IBaseServiceProcessor<T, ID>> practicalProcessor = getPracticalProcessor();
            practicalProcessor.forEach(p -> p.preEntityDeleted(entities));
            entities.forEach(t -> t.setIsDeleted(true));
            repository.saveAll(entities);
            practicalProcessor.forEach(p -> p.postEntityDelete(entities));
        }
    }

}
